﻿using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using System;
using System.Linq;

namespace Utility.NodeGraphs
{
	[NodeGraphEditor (typeof (TreeNodeGraph))]
	public class TreeNodeGraphEditor : NodeGraphEditor
	{
		#region menu
		public override GenericMenu BuildContextMenu (NodeGraph graph)
		{
			var treeGraph = (TreeNodeGraph)graph;

			GenericMenu menu = new GenericMenu ();
			AddMenuItem_AddRootNode<TreeNode> (menu, graph);
			AddMenuItem_AddNode<TreeNode> (menu, graph, "Add Node", "Node");
			AddMenuItem_FormatNodeGraph (menu, graph);

			menu.AddSeparator ("");
			AddMenuItem_ClearAll (menu, graph, "Remove All");

			return menu;
		}

		protected void AddMenuItem_AddRootNode<TRoot> (GenericMenu menu, NodeGraph graph, string text = "Add Root")
			where TRoot : TreeNode
		{
			var treeGraph = (TreeNodeGraph)graph;
			if (treeGraph.RootNodeExist)
			{
				menu.AddDisabledItem (new GUIContent (text));
			}
			else
			{
				Action<TRoot> initNode = node =>
				{
					node.isRoot = true;
				};
				AddMenuItem_AddNode<TRoot> (menu, graph, initNode, text, "Root");
			}
		}

		protected void AddMenuItem_FormatNodeGraph (GenericMenu menu, NodeGraph graph, string text = "Format Tree")
		{
			menu.AddItem (new GUIContent (text), false, () => FormatNodeGraph (graph as TreeNodeGraph));
		}
		#endregion
		#region format
		public virtual Vector2 NodePadding => new Vector2 (50, 20);

		Dictionary<TreeNode, Vector2> subTreeSizeDict = new Dictionary<TreeNode, Vector2> ();

		Vector2 GetSubtreeSize (TreeNode node, Vector2 padding)
		{
			if (!subTreeSizeDict.ContainsKey (node))
			{
				var nodeEditor = NodeEditor.GetEditor (node);
				Vector2 nodeSize = nodeEditor.GetSize (node);

				var childNodes = node.ChildNodes.ToArray ();
				//if is leaf
				if (childNodes.Length == 0)
				{
					subTreeSizeDict[node] = nodeSize;
				}
				else
				{
					float w_childMax = (from child in childNodes
										select GetSubtreeSize (child, padding).x)
									   .Max ();

					float w = nodeSize.x + padding.x + w_childMax;

					float h_childSum = (from child in childNodes
										select GetSubtreeSize (child, padding).y)
									.Sum () + padding.y * (childNodes.Length - 1);

					float h = Mathf.Max (h_childSum, nodeSize.y);

					subTreeSizeDict[node] = new Vector2 (w, h);
				}
			}
			return subTreeSizeDict[node];
		}

		void FormatSubTree (TreeNode subroot, Vector2 padding)
		{
			var childNodes = subroot.ChildNodes.ToArray ();
			if (childNodes.Length == 0)
			{
				return;
			}

			Vector2 subrootSize = NodeEditor.GetEditor (subroot).GetSize (subroot);

			Vector2 pos = subroot.position;
			pos.x += subrootSize.x + padding.x;

			foreach (var child in childNodes)
			{
				child.position = pos;
				FormatSubTree (child, padding);

				Vector2 childSubTreeSize = GetSubtreeSize (child, padding);
				pos.y += childSubTreeSize.y + padding.y;
			}
		}

		public void FormatNodeGraph (TreeNodeGraph graph)
		{
			var root = graph.RootNode;
			if (root != null)
			{
				subTreeSizeDict.Clear ();
				FormatSubTree (root, NodePadding);
			}
		}
		#endregion
	}
}